package client;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.StringTokenizer;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.WindowConstants;

import peer.PeerManager;
import peer.PeerMessageCenter;
import peer.enums.Network;
import util.Util;
import WiFi.WiFiConnectedThread;
import bluetooth.BluetoothConnectedThread;
import exception.NFCException;

public class PresentationApp extends JFrame implements ActionListener, ClientConnectable {

	private final static String newline = "\n";
	
	public static final String NEXT = "^NEXT^";
	public static final String PREVIOUS = "^PREVIOUS^";
	public static final String GOTO = "^GOTO^";
	public static final String START = "^START^";
	public static final String FINISH = "^FINISH^";
	public static final String SLIDENUM = "^SLIDENUM^";
	

	private JTextField entry;
	private JLabel jLabel1;
	private JScrollPane jScrollPane1;
	private JLabel status;
	private JTextArea textArea;
	
	private byte[] arrayFile;
	private int count, slideNum = 0;
	private String aux, filetype ="";
	private long initialCurrentTimeMillis;
	private String fName;

	private boolean isPPT;

	private String fileName, tipoArquivo;



	public PresentationApp() {
		initComponents();
		this.setLocation(600, 400);
		this.setVisible(true);
	}

	/**
	 * This method is called from within the constructor to initialize the form.
	 */

	private void initComponents() {
		entry = new JTextField();
		jLabel1 = new JLabel();
		textArea = new JTextArea();
		status = new JLabel();
		
		

		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setTitle("Demo");

		textArea.setColumns(20);
		textArea.setLineWrap(true);
		textArea.setRows(5);
		textArea.setWrapStyleWord(true);
		textArea.setEditable(false);
		jScrollPane1 = new JScrollPane(textArea);
		jScrollPane1.setAutoscrolls(true);

		jLabel1.setText("Enter a text:");

		entry.addActionListener(this);

		GroupLayout layout = new GroupLayout(getContentPane());
		getContentPane().setLayout(layout);

		// Create a parallel group for the horizontal axis
		ParallelGroup hGroup = layout
				.createParallelGroup(GroupLayout.Alignment.LEADING);

		// Create a sequential and a parallel groups
		SequentialGroup h1 = layout.createSequentialGroup();
		ParallelGroup h2 = layout
				.createParallelGroup(GroupLayout.Alignment.TRAILING);

		// Add a container gap to the sequential group h1
		h1.addContainerGap();
		
		

		// Add a scroll pane and a label to the parallel group h2
		h2.addComponent(jScrollPane1, GroupLayout.Alignment.LEADING,
				GroupLayout.DEFAULT_SIZE, 450, Short.MAX_VALUE);
		h2.addComponent(status, GroupLayout.Alignment.LEADING,
				GroupLayout.DEFAULT_SIZE, 450, Short.MAX_VALUE);

		// Create a sequential group h3
		SequentialGroup h3 = layout.createSequentialGroup();
		h3.addComponent(jLabel1);
		
		h3.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
		h3.addComponent(entry, GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE);

		// Add the group h3 to the group h2
		h2.addGroup(h3);
		// Add the group h2 to the group h1
		h1.addGroup(h2);

		h1.addContainerGap();

		// Add the group h1 to the hGroup
		hGroup.addGroup(GroupLayout.Alignment.TRAILING, h1);
		// Create the horizontal group
		layout.setHorizontalGroup(hGroup);

		// Create a parallel group for the vertical axis
		ParallelGroup vGroup = layout
				.createParallelGroup(GroupLayout.Alignment.LEADING);
		// Create a sequential group v1
		SequentialGroup v1 = layout.createSequentialGroup();
		// Add a container gap to the sequential group v1
		v1.addContainerGap();
		// Create a parallel group v2
		ParallelGroup v2 = layout
				.createParallelGroup(GroupLayout.Alignment.BASELINE);
		v2.addComponent(jLabel1);
		v2.addComponent(entry, GroupLayout.PREFERRED_SIZE,
				GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
		// Add the group v2 tp the group v1
		v1.addGroup(v2);
		v1.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED);
		v1.addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 233,
				Short.MAX_VALUE);
		v1.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED);
		v1.addComponent(status);
		v1.addContainerGap();

		// Add the group v1 to the group vGroup
		vGroup.addGroup(v1);
		// Create the vertical group
		layout.setVerticalGroup(vGroup);
		pack();
	}

	public void addText(String text) {
		textArea.append(text + newline);
		
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		String text = entry.getText();
		
		if(text.length() > 2){
			writeData(text.getBytes());
			
			try {
				if(text.startsWith("B"))
					myWrite(0, text.getBytes());
				else
					myWrite(1, text.getBytes());
				
			} catch (NFCException e) {
				e.printStackTrace();
			}
			
			
			
			
		}else{
			try {
				PeerManager.getInstance().writeProtocol(PeerMessageCenter.createConnectedResponseMessage(true,  Network.Bluetooth));
				text = "createConnectedResponseMessage";
			} catch (NFCException e) {
				e.printStackTrace();
			}
			//send(text);
		}
		this.addText(text);
		entry.setText("");
	}
	
	
	private void myWrite(int selection, byte[] out) throws NFCException {
		
		byte[] array = PeerMessageCenter.formatDataMessage(out);
		switch (selection) {
			case 0:				
				PeerManager.getInstance().bluetoothConnectedThread.write(array);
			case 1:
				WiFiConnectedThread copy;
				synchronized (this) {
					copy = PeerManager.getInstance().wiFiConnectedThread;
					copy.write(array);
				}
				break;
		}
	}	
	
	
	
	@Override
	public void writeData(byte[] array) {
		try {
			PeerManager.getInstance().writeData(array);
		} catch (NFCException e) {
			e.printStackTrace();
		}	
	}


	@Override
	public synchronized void receiveData(byte[] array) {
		String input = new String(array);
//		if(input.trim().equals("##BLUE")){
//			entry.setText("Usando Bluetooth");
//			entry.setBackground(Color.RED);
//			return;
//		}else if(input.trim().equals("###WIFI")){
//			entry.setText("Usando Wifi");
//			entry.setBackground(Color.yellow);
//			return;
//		}
		if(input.startsWith("#F")){		
			receberArquivo(Arrays.copyOfRange(array, 2, array.length), array.length);
			return;
		}
		input = input.trim();
		
		if(input.contains(START)){
			start();
		}else if(input.contains(FINISH)){
			finish();
		}else if(input.contains(NEXT)){
			next();
		}else if(input.contains(PREVIOUS)){
			previous();
		}else if(input.contains(GOTO)){//GOTO = "^GT^" + num + "^";
			StringTokenizer tokenizer = new StringTokenizer(input, "^");
			tokenizer.nextToken();
			String numero = tokenizer.nextToken();
			
			goTo(Integer.parseInt(numero));
		}
		
		//addText(new String(">> " + input.trim()).trim());
	}
	
	public void enviarSlideNum(){
		try {
			writeData(new String(SLIDENUM+getSlideNum()+"^"+this.fileName.trim()+"."+this.tipoArquivo.trim()+"^").getBytes());
		} catch (Exception e) {
			// TODO: handle exception
		}
		
	}
	
	

	private void receberArquivo(byte[] array, int length) {		
		char flag = (char)array[0];
		if(flag == 'T'){
			tipoArquivo = filetype = new String(Arrays.copyOfRange(array, 1, 4));
			isPPT = filetype.equalsIgnoreCase("ppt");
			System.out.println("Tipo do arquivo: " + filetype);
			return;
		}
		if(flag == 'N'){
			int nomeLength = byteArrayToInt(Arrays.copyOfRange(array, 1, 3));
			this.fileName = new String(Arrays.copyOfRange(array, 3, 4 + nomeLength));
			System.out.println("Nome original do arquivo: " + fileName);
			initialCurrentTimeMillis = System.currentTimeMillis();
			return;
		}
		int numSeq = byteArrayToInt(Arrays.copyOfRange(array, 1, 4));
		aux += numSeq + ", ";
		System.out.println("Recebido pacote "+numSeq);
		
		int bytesLidos = byteArrayToInt(Arrays.copyOfRange(array, 4, 9));
		byte[] data = Arrays.copyOfRange(array, 9, bytesLidos+9);
		int dataLength = data.length; 
		//System.out.println("Chegou Pacote num = "+ numSeq + " $ data.lenght= " + dataLength);
		count++;
		if(flag == 'B')//Begin
			arrayFile = data;
		else if(flag == 'R'){//Begin//End
			try {
				arrayFile = Util.concat(arrayFile, data);
			} catch (Exception e) {
				return;
			}
		}
		else{
			String fileName = ""+System.currentTimeMillis();
			fName = fileName +"." +filetype;
			
			arrayFile = Util.concat(arrayFile, data);
			long timeMillis = System.currentTimeMillis();
			long transferTIme = (timeMillis - initialCurrentTimeMillis)/1000;
			
			//System.out.println("DataTotalLength= " + dataTotalength);
			int size = arrayFile.length;
			long throughput = (size/1000)/(transferTIme <= 0? 1 :transferTIme );
			System.out.println("Tempo de  Transferencia" + transferTIme+ "\t a "  + throughput+ " KBytes/sec ");
			System.out.println("Transferencia finalizada. Recebido " + fName + " # num bytes= " + arrayFile.length);
			System.out.println("numero pacotes recebidos= " + count);
			System.out.println("Aux= "+ aux);
			aux = filetype=  ""; count = 0;
			try {
				FileOutputStream fos = new FileOutputStream(fName);
				fos.write(arrayFile, 0, arrayFile.length);
				fos.close();
				start();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
	
	public void start(){
		try {
			Robot robot = new Robot();
			robot.delay(300);
			robot.keyPress(KeyEvent.VK_HOME);
			int l =1;
			try {
		    	File myFile = new File("C:/Users/Arthur/workspace/ServerMaster/"+fName);
		        Desktop.getDesktop().open(myFile);
		        l = (int)(myFile.length()*7)/1000;
		    } catch (IOException ex) {
		    }
			
			System.out.println("Start... isPpt= " + isPPT);
			if(isPPT){
				robot.delay((l<300?300:l));
				robot.keyPress(KeyEvent.VK_F5);
			}else{
				robot.delay((l<300?300:l));
				robot.keyPress(KeyEvent.VK_CONTROL);
				robot.keyPress(KeyEvent.VK_L);
				robot.keyRelease(KeyEvent.VK_CONTROL);
				robot.keyRelease(KeyEvent.VK_L);
			}
			setSlideNum(1);
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}
	
	public void finish(){
		try {
			Robot robot = new Robot();
			robot.keyPress(KeyEvent.VK_ESCAPE);
			setSlideNum(0);
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}
	
	
	
	public void next(){
		try {
			Robot robot = new Robot();
			robot.keyPress(KeyEvent.VK_RIGHT);
			if (isPPT) robot.keyPress(KeyEvent.VK_F5);
			setSlideNum(getSlideNum() + 1);
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}
	
	public void previous(){
		try {
			Robot robot = new Robot();
			robot.keyPress(KeyEvent.VK_LEFT );
			robot.keyPress(KeyEvent.VK_F5);
			setSlideNum(getSlideNum() - 1);
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}
	
	public void goTo(int num){
		try {
			Robot robot = new Robot();
			if (!isPPT){
				robot.keyPress(KeyEvent.VK_CONTROL);
				robot.keyPress(KeyEvent.VK_SHIFT);
				robot.keyPress(KeyEvent.VK_N);
				robot.keyRelease(KeyEvent.VK_CONTROL);
				robot.keyRelease(KeyEvent.VK_SHIFT);
				robot.keyRelease(KeyEvent.VK_N);
				robot.delay(50);
			}
			if(num < 10){
				robot.keyPress(getKeyEvent(num));
			}else{
				String numero = ""+ num;
				for (int i = 0; i < numero.length(); i++) {
					 int car = Integer.parseInt(numero.charAt(i) +"");
					 robot.keyPress(getKeyEvent(car));	
				}
			}
			robot.keyPress(KeyEvent.VK_ENTER);
			if (isPPT) robot.keyPress(KeyEvent.VK_F5);
			setSlideNum(num);
		} catch (AWTException e) {
			e.printStackTrace();
		}
	}
	
	private static int getKeyEvent(int num){
		switch (num) {
			case 1:
				return KeyEvent.VK_1;
			case 2:
				return KeyEvent.VK_2;
			case 3:
				return KeyEvent.VK_3;
			case 4:
				return KeyEvent.VK_4;
			case 5:
				return KeyEvent.VK_5;
			case 6:
				return KeyEvent.VK_6;
			case 7:
				return KeyEvent.VK_7;
			case 8:
				return KeyEvent.VK_8;
			case 9:
				return KeyEvent.VK_9;
			case 0:
				return KeyEvent.VK_0;
		}
		return -1;
		
	}
	
	private static int byteArrayToInt(byte [] b) {
        return Integer.parseInt(new String(b));
	}

	@Override
	public void setConnectedThread(WiFiConnectedThread conTh) {
		//this.conTh = conTh;
	}

	@Override
	public void setBluetoothConnectedThread(BluetoothConnectedThread bluConTh) {
		//this.bluConTh = bluConTh;
				
	}

	public int getSlideNum() {
		return slideNum;
	}

	public void setSlideNum(int slideNum) {
		if(slideNum < 1)
			slideNum = 1;
		else
			this.slideNum = slideNum;
		enviarSlideNum();
	}
	
}
